package cn.iocoder.yudao.module.call.controller.admin.agent;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.call.controller.admin.agent.vo.*;
import cn.iocoder.yudao.module.call.controller.admin.agent.vo.admin.AgentSaveByAdminReqVO;
import cn.iocoder.yudao.module.call.controller.admin.agent.vo.admin.AgentUpdateByAdminReqVO;
import cn.iocoder.yudao.module.call.convert.agent.AgentConverter;
import cn.iocoder.yudao.module.call.dal.dataobject.agent.AgentDO;
import cn.iocoder.yudao.module.call.dal.dataobject.group.GroupDO;
import cn.iocoder.yudao.module.call.framework.client.CallClient;
import cn.iocoder.yudao.module.call.service.agent.AgentService;
import cn.iocoder.yudao.module.call.service.channel.ChannelService;
import cn.iocoder.yudao.module.call.service.group.GroupService;
import cn.iocoder.yudao.module.crm.api.location.NumberLocationApi;
import cn.iocoder.yudao.module.crm.api.location.dto.NumberLocationDTO;
import cn.iocoder.yudao.module.ent.document.NodeLocation;
import cn.iocoder.yudao.module.system.api.extend.ExtendApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;

@Tag(name = "呼叫中心 - 坐席")
@RestController
@RequestMapping("/call/agent")
@Validated
@Slf4j
public class AgentController {

    @Resource
    private AgentService agentService;

    @Resource
    private GroupService groupService;

    @Resource
    private AdminUserApi adminUserApi;

    @Resource
    private NumberLocationApi locationApi;

    @Resource
    private ExtendApi extendApi;

    @Resource
    private ChannelService channelService;

    @PostMapping("/create")
    @Operation(summary = "创建坐席")
    @PreAuthorize("@ss.hasPermission('call:agent:create')")
    public CommonResult<Long> createAgent(@Valid @RequestBody AgentSaveReqVO createReqVO) {
        return success(agentService.createAgent(createReqVO));
    }

    @PostMapping("/create-by-admin")
    @Operation(summary = "超管模式：创建坐席")
    @PreAuthorize("@ss.hasPermission('system:tenant:create')")
    public CommonResult<Boolean> createAgentByAdmin(@RequestBody AgentSaveByAdminReqVO reqVO) {
        return success(agentService.createAgentByAdmin(reqVO));
    }

    @PutMapping("/update")
    @Operation(summary = "更新坐席")
    @PreAuthorize("@ss.hasPermission('call:agent:update')")
    public CommonResult<Boolean> updateAgent(@Valid @RequestBody AgentSaveReqVO updateReqVO) {
        agentService.updateAgent(updateReqVO);
        return success(true);
    }

    @PutMapping("/update-by-admin")
    @Operation(summary = "超管模式：更新坐席")
    @PreAuthorize("@ss.hasPermission('system:tenant:update')")
    public CommonResult<Boolean> updateAgentByAdmin(@Valid @RequestBody AgentUpdateByAdminReqVO updateReqVO) {
        agentService.updateAgentByAdmin(updateReqVO);
        return success(true);
    }

    @PutMapping("/batch-update-by-admin")
    @Operation(summary = "超管模式：批量更新坐席")
    @PreAuthorize("@ss.hasPermission('system:tenant:update')")
    public CommonResult<Boolean> batchUpdateAgentByAdmin(@Valid @RequestBody AgentUpdateByAdminReqVO updateReqVO) {
        agentService.batchUpdateAgentByAdmin(updateReqVO);
        return success(true);
    }


    @DeleteMapping("/delete")
    @Operation(summary = "删除坐席")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('call:agent:delete')")
    public CommonResult<Boolean> deleteAgent(@RequestParam("id") Long id) {
        agentService.deleteAgent(id);
        return success(true);
    }

    @DeleteMapping("/delete-by-admin")
    @Operation(summary = "删除坐席")
    @Parameter(name = "id", description = "编号", required = true)
    @Parameter(name = "tenantId", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('system:tenant:delete')")
    public CommonResult<Boolean> deleteAgent(@RequestParam("id") Long id, @RequestParam("tenantId") Long tenantId) {
        TenantUtils.execute(tenantId, () -> {
            agentService.deleteAgent(id);
        });

        return success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "获得坐席")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('call:agent:query')")
    public CommonResult<AgentRespVO> getAgent(@RequestParam("id") Long id) {
        AgentDO agent = agentService.getAgent(id);
        return success(BeanUtils.toBean(agent, AgentRespVO.class));
    }

    @GetMapping("/info")
    @Operation(summary = "获得坐席")
    public CommonResult<AgentRespVO> getAgentByLoginUser() {
        AgentDO agent = agentService.getAgent();
        return success(BeanUtils.toBean(agent, AgentRespVO.class));
    }

    @GetMapping("/get-by-admin")
    @Operation(summary = "获得坐席")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @Parameter(name = "tenantId", description = "企业租户ID", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('system:tenant:query')")
    public CommonResult<AgentRespVO> getAgentByAdmin(@RequestParam("id") Long id, @RequestParam("tenantId") Long tenantId) {
        return TenantUtils.execute(tenantId, () -> {
            AgentDO agent = agentService.getAgent(id);
            return success(BeanUtils.toBean(agent, AgentRespVO.class));
        });
    }


    @GetMapping("/page")
    @Operation(summary = "获得坐席分页")
    @PreAuthorize("@ss.hasPermission('call:agent:query')")
    public CommonResult<PageResult<AgentRespVO>> getAgentPage(@Valid AgentPageReqVO pageReqVO) {
        PageResult<AgentDO> pageResult = agentService.getAgentPage(pageReqVO);
        List<AdminUserRespDTO> userList = adminUserApi.getUserList(pageResult.getList().stream().map(AgentDO::getOwnerUserId).collect(Collectors.toList()));
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userList.stream().map(AdminUserRespDTO::getId).collect(Collectors.toList()));
        Map<Long, GroupDO> groupMap = groupService.getGroupMap();
        return success(AgentConverter.INSTANCE.convert0(pageResult, userMap, groupMap));
    }

    @GetMapping("/page-by-admin")
    @Operation(summary = "超管模式：获得坐席分页")
    @PreAuthorize("@ss.hasPermission('system:tenant:query')")
    public CommonResult<PageResult<AgentRespVO>> getAgentPageByAdmin(@Valid AgentPageReqVO pageReqVO) {
        return TenantUtils.execute(pageReqVO.getTenantId(), () -> getAgentPage(pageReqVO));
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出坐席 Excel")
    @PreAuthorize("@ss.hasPermission('call:agent:export')")
    @OperateLog(type = EXPORT)
    public void exportAgentExcel(@Valid AgentPageReqVO pageReqVO,
                                 HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<AgentDO> list = agentService.getAgentPage(pageReqVO).getList();
        // 导出 Excel
        ExcelUtils.write(response, "坐席.xls", "数据", AgentRespVO.class,
                BeanUtils.toBean(list, AgentRespVO.class));
    }

    @PostMapping("/simple-call")
    @Operation(summary = "坐席点呼")
    public CommonResult<CallRespVO> simpleCall(@Valid @RequestBody CallReqVO callReqVO) {
        CallRespVO callRespVO = agentService.simpleCall(callReqVO);
        return success(callRespVO);
    }

    @PostMapping("/active")
    @Operation(summary = "坐席心跳")
    @OperateLog(enable = false)
    public CommonResult<Boolean> active() {
        agentService.active(getLoginUserId());
        return success(true);
    }

    @GetMapping("/get-call-by-no")
    @Operation(summary = "根据话单获取通话记录")
    @Parameter(name = "reqNo", description = "话单No", required = true)
    public CommonResult<String> getCallRespByReqNo(@Valid @RequestParam("reqNo") String reqNo) {
        return success(agentService.getCallByReqNo(reqNo));
    }


    @PostMapping("/map-call-id")
    @Operation(summary = "创建话机盒子callId和本地reqNo 映射")
    public CommonResult<String> handleCallIdMap(@RequestBody Map<String, String> params) {
        return success(agentService.mapCallIdAndReqNo(params));
    }


    @GetMapping("/get-channel")
    @Operation(summary = "根据话机模式获取企业配置的外呼渠道")
    @Parameter(name = "phoneMode", description = "外呼模式", required = true, example = "box")
    public CommonResult<Long> checkChannel(@Valid @RequestParam("phoneMode") String phoneMode) {
        return success(agentService.getChannel(phoneMode));
    }

    @PostMapping("/handle-agent")
    @Operation(summary = "坐席操作")
    public CommonResult<Boolean> handleAgent(@Valid @RequestBody Map<String, Object> data) {
        return success(agentService.handleAgent(data));
    }

    @PostMapping("/update-agent-status")
    @Operation(summary = "更新坐席状态")
    public CommonResult<Boolean> updateAgentStatus(@Valid @RequestBody Map<String, String> data) {
        return success(agentService.updateAgentStatus(data));
    }

    @GetMapping("/get-account-info")
    @Operation(summary = "获取外呼sip账号")
    @Parameter(name = "channelId", description = "渠道编号", required = true, example = "1024")
    public CommonResult<JSONObject> getAccountInfo(@RequestParam("channelId") Long channelId) {
        JSONObject accountInfo = agentService.getAccountInfo(channelId);
        return success(accountInfo);
    }


    @GetMapping("/get-customer-info")
    @Operation(summary = "获取客户信息")
    @Parameter(name = "reqNo", description = "话单id", required = true, example = "1024")
    public CommonResult<Map<String, Object>> getCustomerInfo(@RequestParam("reqNo") String reqNo) {
        Map<String, Object> result = agentService.getCustomerInfo(reqNo);
        return success(result);
    }


    @PostMapping("/add-follow-record")
    @Operation(summary = "写跟进")
    public CommonResult<Boolean> addFollowRecord(@Valid @RequestBody CallAddFollowRecordReqVO param) {
        agentService.addCustomerFollowRecord(param);
        return success(true);
    }

    @GetMapping("/get-location")
    @Operation(summary = "获取号码归属地")
    public CommonResult<NumberLocationDTO> getLocation(@RequestParam("number") String number) {
        return success(locationApi.getLocation(number));
    }


    @PostMapping("/monitor")
    @Operation(summary = "坐席监控")
    @OperateLog(enable = false)
    @PreAuthorize("@ss.hasPermission('call:agent:monitor')")
    public CommonResult<JSONObject> monitor(@Valid @RequestBody AgentMonitorReqVO params) {
        //查询坐席状态
        JSONObject agentState = extendApi.request("/agent/monitor", JSONUtil.toJsonStr(params));
        return success(agentState);
    }

    @PostMapping("/forceLogout")
    @Operation(summary = "坐席监控-坐席登出")
    @PreAuthorize("@ss.hasPermission('call:agent:monitor')")
    public CommonResult<Boolean> forceLogout(@RequestBody Map<String, String> data) {
        CallClient callClient = channelService.getTenantCallClient(TenantContextHolder.getTenantId());
        return success(callClient.forceLogout(data.get("agentId")));
    }

    @PostMapping("/forceNotReady")
    @Operation(summary = "坐席监控-坐席置忙")
    @PreAuthorize("@ss.hasPermission('call:agent:monitor')")
    public CommonResult<Boolean> forceNotReady(@RequestBody Map<String, String> data) {
        CallClient callClient = channelService.getTenantCallClient(TenantContextHolder.getTenantId());
        return success(callClient.forceNotReady(data.get("agentId")));
    }

    @PostMapping("/forceReady")
    @Operation(summary = "坐席监控-坐席置闲")
    @PreAuthorize("@ss.hasPermission('call:agent:monitor')")
    public CommonResult<Boolean> forceReady(@RequestBody Map<String, String> data) {
        CallClient callClient = channelService.getTenantCallClient(TenantContextHolder.getTenantId());
        return success(callClient.forceReady(data.get("agentId")));
    }

    @PostMapping("/forceSkillChange")
    @Operation(summary = "坐席监控-坐席改签")
    @PreAuthorize("@ss.hasPermission('call:agent:monitor')")
    public CommonResult<Boolean> forceSkillChange(@Valid @RequestBody AgentSkillChangeReqVO reqVO) {
        CallClient callClient = channelService.getTenantCallClient(TenantContextHolder.getTenantId());
        List<Map<String, Object>> skills = new ArrayList<>();
        for (AgentSkillChangeReqVO.SkillData skill : reqVO.getSkills()) {
            Map<String, Object> tmp = new HashMap<>();
            tmp.put("skill_id", skill.getSkillId());
            tmp.put("skill_level", skill.getSkillLevel());
            skills.add(tmp);
        }
        return success(callClient.forceSkillChange(reqVO.getAgentId(), skills));
    }



}